"""Copyright 2011 Google Inc.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.


__author__ = "nratani@google.com (Nadim Ratani)"
__version__ = 1.0

Wallet Barista Coffee Shop Example.

This example demonstrates the flow of a Google Payment Express implementation.
"""

import os
import time

from google.appengine.ext import webapp
from google.appengine.ext.webapp import template
from google.appengine.ext.webapp.util import run_wsgi_app
import third_party.jwt as jwt


class Config:
  """Holds application and merchant configuration settings."""

  def __init__(self):
    """Replace the variables below with appropriate values."""
    self.iss = "[iss]",
    self.signing_key = "[signing_key]",
    self.origin = "[origin]",
    self.js_url = (
        "https://wallet.sandbox.google.com/online/merchant/merchant.js")

CONFIG = Config()


class Baristas(webapp.RequestHandler):
  """The main handler which displays the initial drink selection page."""

  def get(self):
    """Renders the index.html template."""

    template_values = {}
    path = os.path.join(os.path.dirname(__file__), "templates/index.html")
    self.response.out.write(template.render(path, template_values))


class Order(webapp.RequestHandler):
  """The Order handler for Wallet Baristas, which handles ordering details."""

  def get(self):
    """Generate the masked wallet JWT and embed it directly into the HTML."""

    masked_wallet_request_jwt = jwt.encode({
        "iss": CONFIG.iss,
        "origin": CONFIG.origin,
        "aud": "Google",
        "iat": int(time.time()),
        "typ": "google/paymentexpress/v1/masked/request",
        "selectors": {
            "pay": {
                "type": "PAYMENT_INSTRUMENT",
            },
            "ship": {
                "type": "SHIPPING_ADDRESS",
            }
        }
    }, CONFIG.signing_key)

    template_values = {
        "masked_wallet_request_jwt": masked_wallet_request_jwt,
        "js_url": CONFIG.js_url
        }

    path = os.path.join(os.path.dirname(__file__), "templates/order.html")
    self.response.out.write(template.render(path, template_values))


class MaskedWalletJWTHandler(webapp.RequestHandler):
  """The masked wallet handler, which receives the masked wallet details."""

  def post(self):
    """Reads the masked wallet response and creates full wallet request."""

    form_drink = self.request.get("drink")
    form_milk = self.request.get("milk")
    form_total = self.request.get("formTotal")
    encoded_masked_wallet_jwt = str(self.request.get("maskedWalletJWT"))

    if form_milk == "none":
      form_milk = None

    order_description = ("%s" % form_drink)

    decoded_masked_wallet = (
        jwt.decode(encoded_masked_wallet_jwt, CONFIG.signing_key))

    # examine payment credentials
    payment_credentials = (
        decoded_masked_wallet["selection"]["pay"]["payment_instrument"])

    # examine shipping address
    shipping_address = decoded_masked_wallet["selection"]["ship"]

    # generate another masked wallet request JWT, similar to the original one
    # optionally with exclude objects to not be accepted. Notice that there
    # is now a google_transaction_id.
    masked_wallet_request_jwt = jwt.encode({
        "iss": CONFIG.iss,
        "origin": CONFIG.origin,
        "aud": "Google",
        "iat": int(time.time()),
        "typ": "google/paymentexpress/v1/masked/request",
        "google_transaction_id": decoded_masked_wallet["google_transaction_id"],
        "selectors": {
            "pay": {
                "type": "PAYMENT_INSTRUMENT",
            },
            "ship": {
                "type": "SHIPPING_ADDRESS",
            }
        }
    }, CONFIG.signing_key)

    # generate a full wallet request JWT
    full_wallet_request_jwt = jwt.encode({
        "iss": CONFIG.iss,
        "origin": CONFIG.origin,
        "aud": "Google",
        "iat": int(time.time()),
        "typ": "google/paymentexpress/v1/full/request",
        "google_transaction_id": decoded_masked_wallet["google_transaction_id"],
        "cart": {
            "total_price": float(form_total),
            "currency": "USD",
            "line_items": [{
                "description": order_description,
                "quantity": 1,
                "unit_price": float(form_total),
                "total_price": float(form_total),
                "currency": "USD"
            }]
        }
    }, CONFIG.signing_key)

    template_values = {
        "payment_instrument": (
            decoded_masked_wallet["selection"]["pay"]["payment_instrument"]),
        "shipping_address": (
            decoded_masked_wallet["selection"]["ship"]["shipping_address"]),
        "masked_wallet_request_jwt": masked_wallet_request_jwt,
        "full_wallet_request_jwt": full_wallet_request_jwt,
        "order_description": order_description,
        "total_price": form_total,
        "js_url": CONFIG.js_url
    }
    path = os.path.join(os.path.dirname(__file__), "templates/confirm.html")
    self.response.out.write(template.render(path, template_values))


class FullWalletJWTHandler(webapp.RequestHandler):
  """The full wallet handler, which receives the full wallet details."""

  def post(self):
    """Receives full wallet, decrypts payment credentials, displays receipt."""

    # retreive the order description to display it back to the user
    # a real implementation would not use this technique
    order_description = self.request.get("orderDescription")

    # retrieve the full wallet request JWT to print out what the user purchased
    # a real implementation would not use this technique
    encoded_full_wallet_request_jwt = str(self.request.get("fullWalletRequestJWT"))

    decoded_full_wallet_request_jwt = (
        jwt.decode(encoded_full_wallet_request_jwt, CONFIG.signing_key))

    # retrieve the full wallet details
    encoded_full_wallet_jwt = str(self.request.get("fullWalletJWT"))

    decoded_full_wallet_jwt = jwt.decode(encoded_full_wallet_jwt, CONFIG.signing_key)

    # get payment credentials
    encrypted_full_card_number = (
        decoded_full_wallet_jwt["selection"]["pay"]["payment_instrument"]["full_card_number"])

    encrypted_cvc = decoded_full_wallet_jwt["selection"]["pay"]["payment_instrument"]["cvc"]

    # Decrypt ...

    # Validate payment credentials ...

    # Process payment ...

    # Make a transaction status notification JWT
    transaction_status_notification_jwt = jwt.encode({
        "aud": "Google",
        "google_transaction_id": decoded_full_wallet_jwt["google_transaction_id"],
        "iat": int(time.time()),
        "iss": CONFIG.iss,
        "status": "SUCCESS",  # processing was successful or not
        "typ": "google/paymentexpress/v1/transactionstatus"
    }, CONFIG.signing_key)

    template_values = {
        "order_description": order_description,
        "total_price": decoded_full_wallet_request_jwt["cart"]["total_price"],
        "payment_instrument": decoded_full_wallet_jwt["selection"]["pay"]["payment_instrument"],
        "transaction_status_notification_jwt": transaction_status_notification_jwt,
        "js_url": CONFIG.js_url
    }
    path = os.path.join(os.path.dirname(__file__), "templates/receipt.html")
    self.response.out.write(template.render(path, template_values))


application = webapp.WSGIApplication([("/", Baristas),
                                      ("/order", Order),
                                      ("/confirm", MaskedWalletJWTHandler),
                                      ("/receipt", FullWalletJWTHandler)],
                                     debug=True)


def main():
  run_wsgi_app(application)

if __name__ == "__main__":
  main()
